package test.coin;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.Request;
import org.web3j.protocol.core.methods.response.EthGasPrice;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.core.methods.response.EthTransaction;
import org.web3j.protocol.core.methods.response.Transaction;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.Contract;
import org.web3j.utils.Numeric;

public class Erc20api {
	public static final String TRANSFER = "transfer";
	private static final String web3j_url = "https://ropsten.infura.io/v3/98b15944645e4771b8de222c6b31214d";
	public static final Web3j web3j = Web3j.build(new HttpService(web3j_url));
	public static final Long GAS_LIMIT = 10000L;
	public static final String log_address_start = "0x000000000000000000000000";
	
	public Erc20api() {

	}

	/**
	 * 获取nonce
	 * 
	 * @param from 转账地址
	 * @return BigInteger类型nonce
	 * @throws ExecutionException
	 * @throws InterruptedException
	 */
	public static BigInteger getNonce(String from) throws InterruptedException, ExecutionException {
		EthGetTransactionCount transactionCount;
		BigInteger nonce = null;

		transactionCount = web3j.ethGetTransactionCount(from, DefaultBlockParameterName.LATEST).sendAsync().get();
		nonce = transactionCount.getTransactionCount();

		return nonce;
	}

	/**
	 * 获取gas
	 * 
	 * @return BigInteger 当前gas
	 * @throws ExecutionException
	 * @throws InterruptedException
	 */
	public static BigInteger getGasPrice() throws InterruptedException, ExecutionException {
		BigInteger gas = new BigInteger("100000000000");

		EthGasPrice ethGasPrice = web3j.ethGasPrice().sendAsync().get();
		if (ethGasPrice != null)
			gas = ethGasPrice.getGasPrice();		 
		return gas;
	}

	/**
	 * 合约方法
	 * 
	 * @param to    收账地址
	 * @param value 转账额
	 * @return Function
	 */
	public static Function tranFunction(String to, BigInteger value) {
		Function function = null;

		function = new Function(TRANSFER, Arrays.asList(new Address(to), new Uint256(value)),
				Collections.singletonList(new TypeReference<Type>() {
				}));

		return function;
	}

	/**
	 * 发送交易
	 * 
	 * @param hexValue hex
	 * @return 交易
	 * @throws ExecutionException
	 * @throws InterruptedException
	 */
	public static String sendTransaction(String hexValue) throws InterruptedException, ExecutionException {
		EthSendTransaction transaction = null;
		transaction = web3j.ethSendRawTransaction(hexValue).sendAsync().get();
		if (transaction.hasError()) {
			System.out.println("Web3j --> ethSendRawTransaction:" + transaction.getError().getMessage());
		}
		if (transaction != null) {
			// 获得到transactionHash后就可以到以太坊的网站上查询这笔交易的状态了		
			return transaction.getTransactionHash(); 	
		}
		return null;
	}
	public static Transaction getBlockByHash(String txhash)  {
		
		Request<?, EthTransaction> pp=web3j.ethGetTransactionByHash(txhash);
		try {
			Transaction t=pp.send().getResult();		
			return t;
		}catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	public static Transaction getTransactionByHash(String txhash)  {
		
		  Request<?, EthTransaction> pp=web3j.ethGetTransactionByHash(txhash);
		try {
			Transaction t=pp.send().getResult();
		
			return t;
		}catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static String transferERC20Token(String 合约地址, String 转出人, String 转出人密钥, String 转入人, BigInteger 转多少)
			throws InterruptedException, ExecutionException {
//加载转账所需的凭证，用私钥
		Credentials credentials = Credentials.create(转出人密钥);
//获取nonce，交易笔数
		BigInteger nonce = getNonce(转出人);
//System.out.println("燃气交易笔数="+nonce);
//get gasPrice
		BigInteger gasPrice = getGasPrice();
//System.out.println("燃气价格="+gasPrice);
//BigInteger gasLimit = BigInteger.valueOf(Constants.GAS_LIMIT);
		BigInteger gasLimit = Contract.GAS_LIMIT;
//System.out.println("燃气限量="+gasLimit);
//创建RawTransaction交易对象
		Function function = tranFunction(转入人, 转多少);

		String encodedFunction = FunctionEncoder.encode(function);

		RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, 合约地址,
				encodedFunction);

//签名Transaction，这里要对交易做签名
		byte[] signMessage = TransactionEncoder.signMessage(rawTransaction, credentials);

		String hexValue = Numeric.toHexString(signMessage);
		// System.out.println("签名=" + hexValue);
//发送交易
		return sendTransaction(hexValue);
	}

	public static String transferETH(String 转出人, String 转出人密钥, String 转入人, BigInteger 转多少) throws InterruptedException, ExecutionException {
		// 设置需要的矿工费
		// BigInteger GAS_PRICE = BigInteger.valueOf(22_000_000_000L);
		// BigInteger GAS_LIMIT = BigInteger.valueOf(4_300_000);
		// 转账人私钥
		Credentials credentials = Credentials.create(转出人密钥);
		// Credentials credentials = WalletUtils.loadCredentials(
		// "123",
		// "src/main/resources/UTC--2018-03-01T05-53-37.043Z--d1c82c71cc567d63fd53d5b91dcac6156e5b96b3");
		// 获取nonce，交易笔数
		BigInteger nonce = getNonce(转出人);
		// System.out.println("燃气交易笔数="+nonce);
		// get gasPrice
		BigInteger gasPrice = getGasPrice();
		// System.out.println("燃气价格="+gasPrice);
		// BigInteger gasLimit = BigInteger.valueOf(Constants.GAS_LIMIT);
		BigInteger gasLimit = Contract.GAS_LIMIT;
		// 创建交易，这里是转0.5个以太币
		// BigInteger value = Convert.toWei(转多少, Convert.Unit.ETHER).toBigInteger();
		RawTransaction rawTransaction = RawTransaction.createEtherTransaction(nonce, gasPrice, gasLimit, 转入人, 转多少);
		// 签名Transaction，这里要对交易做签名
		byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
		String hexValue = Numeric.toHexString(signedMessage);
		// 发送交易
		return sendTransaction(hexValue);

	}

}
